--[[
  端口8848和9006 成都移动银行二期系统接口
  8个字节包长(不含自身)+4个字节交易代码+XML
]]
require("apm_core")
require("ApmXml")

local G_DEBUG = true

if G_DEBUG == false then
    function logDebug(fmt,...) end
    function logInfo(fmt,...) end
    function logWarn(fmt,...) end
    function logError(fmt,...) end
    function logFatal(fmt,...) end
end

local t_xml_tree
local s_trans_name
local s_channel_name
local s_rspcode
local s_rspmsg
local s_flowno

local function parseIp(ip)
    local _, _, value = string.find(ip, "(%d+.%d+)$")
    return value == nil and "" or value
end

--- 协议判断
-- return
-- true; false
local function protocol_detect(s_payload)
    if s_payload == nil then return false end

    t_xml_tree = ApmXml.load(s_payload, "UTF-8")

    if t_xml_tree == nil then return false end

    return ApmXml.getValue(t_xml_tree, "/Transaction") ~= nil
end

local arr_trans_code = {};
arr_trans_code["0003"] = "根据客户号（或证件号码）查询客户信息";
arr_trans_code["0004"] = "活期转其它储种开户";
arr_trans_code["0006"] = "子帐户销户转活期主帐户";
arr_trans_code["0008"] = "本人活期帐户间互转";
arr_trans_code["0009"] = "行内互转";
arr_trans_code["0014"] = "通知存款取款";
arr_trans_code["0015"] = "个人帐户挂失";
arr_trans_code["0016"] = "自动转存预约登记";
arr_trans_code["0017"] = "自动转存预约撤销";
arr_trans_code["0018"] = "通知存款取款预约";
arr_trans_code["0019"] = "通知存款取款预约查询";
arr_trans_code["0020"] = "通知存款取款预约取消";
arr_trans_code["4099"] = "通知存款取款预约查询所有有效记录";
arr_trans_code["0022"] = "对私存款户查询帐户信息";
arr_trans_code["0023"] = "一卡通户查询卡信息";
arr_trans_code["0024"] = "一卡通查询子帐户";
arr_trans_code["0025"] = "对公存款户查询帐户信息";
arr_trans_code["0027"] = "查询交易明细";
arr_trans_code["0072"] = "查询客户所有定期及通知存款账户";
arr_trans_code["0013"] = "整整定期存款销户";
arr_trans_code["0028"] = "根据还款帐号查询贷款帐号";
arr_trans_code["0034"] = "对账";
arr_trans_code["0041"] = "信用卡帐户查询";
arr_trans_code["0043"] = "信用卡未出帐单交易明细查询";
arr_trans_code["0044"] = "信用卡历史账单头查询";
arr_trans_code["0045"] = "信用卡历史账单明细查询";
arr_trans_code["0046"] = "信用卡自扣还款账号查询和维护";
arr_trans_code["0047"] = "信用卡灵活分期申请/撤销交易";
arr_trans_code["0048"] = "信用卡分期付款申请件查询";
arr_trans_code["0049"] = "信用卡分期付款申请件明细查询";
arr_trans_code["0050"] = "信用卡灵活分期付款交易撤销分期";
arr_trans_code["0051"] = "信用卡交易提前还款申请";
arr_trans_code["0052"] = "信用卡分期付款交易明细查询";
arr_trans_code["0053"] = "信用卡积分查询";
arr_trans_code["0056"] = "信用卡挂失";
arr_trans_code["0057"] = "信用卡客户资料查询及更新接口";
arr_trans_code["0060"] = "信用卡手工还款";
arr_trans_code["1008"] = "大小额支付接口";
arr_trans_code["1010"] = "查询支付系统工作日";
arr_trans_code["1027"] = "贷款帐户查询";
arr_trans_code["1028"] = "贷款还款明细查询";
arr_trans_code["1029"] = "贷款还款计划查询";
arr_trans_code["1065"] = "还款账号对应贷款账号查询";
arr_trans_code["0091"] = "预约信息登记";
arr_trans_code["0092"] = "预约信息撤销";
arr_trans_code["0093"] = "预约信息查询";
arr_trans_code["3085"] = "联网行发起银转证";
arr_trans_code["3086"] = "联网行发起证转银";
arr_trans_code["3087"] = "流水查询";
arr_trans_code["3088"] = "资金账户查询";
arr_trans_code["3089"] = "签约关系查询";
arr_trans_code["3007"] = "理财产品购买";
arr_trans_code["3010"] = "理财产品赎回";
arr_trans_code["3011"] = "允许撤单流水查询";
arr_trans_code["3012"] = "客户撤单";
arr_trans_code["3017"] = "定向预约查询";
arr_trans_code["3020"] = "客户签约银行账号信息查询";
arr_trans_code["3022"] = "客户理财产品份额查询";
arr_trans_code["3026"] = "客户历史委托查询";
arr_trans_code["3030"] = "理财产品信息查询";
arr_trans_code["3061"] = "客户历史成交查询";
arr_trans_code["3055"] = "基金产品转换";
arr_trans_code["3047"] = "变更分红方式";
arr_trans_code["3048"] = "定期定额开通";
arr_trans_code["3051"] = "定期定额信息查询";
arr_trans_code["3050"] = "定期定额关闭";
arr_trans_code["3049"] = "定期定额修改";
arr_trans_code["B009"] = "个人外汇账户列表查询";
arr_trans_code["B010"] = "个人外汇账户交易明细查询";
arr_trans_code["5000"] = "手机银行对私账户密码校验";
arr_trans_code["4098"] = "账户下挂到移动银行";
arr_trans_code["1040"] = "网银员工编号校验";
arr_trans_code["5001"] = "客户信息查询";
arr_trans_code["5002"] = "客户签约";
arr_trans_code["5003"] = "解约移动银行";
arr_trans_code["5004"] = "获取客户下挂帐户信息列表";
arr_trans_code["5005"] = "添加客户下挂帐户";
arr_trans_code["5006"] = "修改客户下挂帐户信息";
arr_trans_code["5007"] = "删除客户下挂帐户";
arr_trans_code["5008"] = "查询转账联系人";
arr_trans_code["5009"] = "添加转账联系人";
arr_trans_code["5010"] = "修改转账联系人";
arr_trans_code["5011"] = "删除转账联系人";
arr_trans_code["5012"] = "修改客户明细信息";
arr_trans_code["5013"] = "查询工资条信息";
arr_trans_code["5014"] = "查询银行行别代码信息";
arr_trans_code["5015"] = "查询银行信息";
arr_trans_code["5017"] = "手机号查询默认账户";
arr_trans_code["5018"] = "查询大额转账联系人";
arr_trans_code["5019"] = "添加大额转账联系人";
arr_trans_code["5020"] = "修改大额转账联系人";
arr_trans_code["5021"] = "删除大额转账联系人";
arr_trans_code["5031"] = "公众渠道查询";
arr_trans_code["5032"] = "公众渠道客户签约";
arr_trans_code["5033"] = "公众账号修改";
arr_trans_code["6001"] = "客户开通/关闭";
arr_trans_code["6002"] = "企业基本信息查询";
arr_trans_code["6003"] = "企业账户列表查询";
arr_trans_code["6004"] = "授权模式列表查询";
arr_trans_code["6005"] = "授权模式明细查询";
arr_trans_code["6006"] = "开通业务列表查询";
arr_trans_code["6007"] = "操作员查询";
arr_trans_code["6008"] = "企业管理授权列表";
arr_trans_code["6009"] = "管理指令列表查询";
arr_trans_code["6010"] = "操作员维护指令列表详情查询";
arr_trans_code["6011"] = "账户维护指令详情查询";
arr_trans_code["6013"] = "授权模式指令详情查询";
arr_trans_code["6014"] = "操作员信息修改";
arr_trans_code["6015"] = "修改账户别名";
arr_trans_code["6016"] = "查询企业账户额度列表";
arr_trans_code["6018"] = "登录";
arr_trans_code["6021"] = "查询指令列表";
arr_trans_code["6022"] = "获取某交易类型的指令列表";
arr_trans_code["6023"] = "查询指令历史详情";
arr_trans_code["6024"] = "转账指令提交";
arr_trans_code["6025"] = "转账指令授权";
arr_trans_code["6026"] = "转账流水查询";
arr_trans_code["6027"] = "理财购买指令提交";
arr_trans_code["6028"] = "理财购买指令授权";
arr_trans_code["6029"] = "理财撤销指令提交";
arr_trans_code["6030"] = "理财撤销指令授权";
arr_trans_code["6031"] = "理财赎回指令提交";
arr_trans_code["6032"] = "理财赎回指令授权";
arr_trans_code["6037"] = "理财交易流水查询";
arr_trans_code["6038"] = "理财客户信息变更指令提交";
arr_trans_code["6039"] = "理财客户信息变更指令授权";
arr_trans_code["6040"] = "理财客户信息变更流水查询";
arr_trans_code["6041"] = "基金购买指令提交";
arr_trans_code["6042"] = "基金购买指令授权";
arr_trans_code["6043"] = "基金撤单指令提交";
arr_trans_code["6044"] = "基金撤单指令授权";
arr_trans_code["6045"] = "基金转换指令提交";
arr_trans_code["6046"] = "基金转换指令授权";
arr_trans_code["6047"] = "基金分红方式变更指令提交";
arr_trans_code["6048"] = "基金分红方式变更指令授权";
arr_trans_code["6049"] = "基金赎回指令提交";
arr_trans_code["6050"] = "基金赎回指令授权";
arr_trans_code["6051"] = "基金交易流水查询";
arr_trans_code["6052"] = "基金定投开通指令提交";
arr_trans_code["6053"] = "基金定投开通指令授权";
arr_trans_code["6054"] = "基金定投修改指令提交";
arr_trans_code["6055"] = "基金定投修改指令授权";
arr_trans_code["6056"] = "基金定投关闭指令提交";
arr_trans_code["6057"] = "基金定投关闭指令授权";
arr_trans_code["6058"] = "基金定投流水查询";
arr_trans_code["6059"] = "活转定指令提交";
arr_trans_code["6060"] = "活转定指令授权";
arr_trans_code["6061"] = "定转活指令提交";
arr_trans_code["6062"] = "定转活指令授权";
arr_trans_code["6063"] = "定活互转流水查询";
arr_trans_code["6064"] = "通知存款开立指令提交";
arr_trans_code["6065"] = "通知存款开立指令授权";
arr_trans_code["6066"] = "通知存款开立流水查询";
arr_trans_code["6067"] = "通知存款支取指令提交";
arr_trans_code["6068"] = "通知存款支取指令授权";
arr_trans_code["6069"] = "通知存款支取取消指令提交";
arr_trans_code["6070"] = "通知存款支取取消指令授权";
arr_trans_code["6071"] = "通知存款预约取款指令提交";
arr_trans_code["6072"] = "通知存款预约取款指令授权";
arr_trans_code["6073"] = "通知存款支取流水查询";
arr_trans_code["6074"] = "转账手续费查询";
arr_trans_code["6075"] = "转账流水列表查询";
arr_trans_code["6076"] = "理财交易流水查询";
arr_trans_code["6077"] = "理财客户信息变更流水列表查询";
arr_trans_code["6078"] = "基金交易流水列表查询";
arr_trans_code["6079"] = "基金定投流水列表查询";
arr_trans_code["6080"] = "定活互转流水列表查询";
arr_trans_code["6081"] = "通知存款开立流水列表查询";
arr_trans_code["6082"] = "通知存款支取流水列表查询";
arr_trans_code["7001"] = "更新外汇牌";
arr_trans_code["7002"] = "查询外汇牌";
arr_trans_code["8001"] = "柜员交易密钥生成、查询";
arr_trans_code["8002"] = "柜员签到";
arr_trans_code["8003"] = "柜员签退";
arr_trans_code["8004"] = "个人客户信息管理";
arr_trans_code["8005"] = "对私开卡";
arr_trans_code["8006"] = "单位客户信息管理";
arr_trans_code["8007"] = "单位结算账户开立";
arr_trans_code["8008"] = "单位账户开户进度查询";
arr_trans_code["8009"] = "公司信息列表查询";
arr_trans_code["8010"] = "对私卡激活";


local arr_channel_id = {};
arr_channel_id["01"] = "网上银行";
arr_channel_id["02"] = "手机银行";
arr_channel_id["03"] = "短信银行";
arr_channel_id["04"] = "手机银行柜面";

local arr_chno = {};
arr_chno["1001"] = "网上银行";
arr_chno["1002"] = "手机银行";
arr_chno["1003"] = "短信银行";
arr_chno["1004"] = "手机银行柜面";

--- 解析请求
-- return
-- true: 解析成功; false: 解析失败
local function trans_parse_request(ApmData)
    -- 交易代码
    local s_trans_code = ApmXml.getValue(t_xml_tree, "/Transaction/TransHeader/TransCode/text()");
    if s_trans_code ~= nil then
        s_trans_code = string.trim(s_trans_code);
        s_trans_name = arr_trans_code[s_trans_code];
        if s_trans_name == nil then s_trans_name = s_trans_code end
        ApmData.replaceField("transaction.type_code", s_trans_code);
        ApmData.replaceField("transaction.type_name", s_trans_name);
    end

    -- 交易渠道
    local s_chno = ApmXml.getValue(t_xml_tree, "/Transaction/TransHeader/ChNo/text()");
    if s_chno ~= nil then
        s_chno = string.trim(s_chno)
        s_channel_name = arr_chno[s_chno]
        if s_channel_name == nil then s_channel_name = s_chno end
        ApmData.replaceField("transaction.channel_code", s_chno)
        ApmData.replaceField("transaction.channel_name", s_channel_name)
    else
        local s_channel_id = ApmXml.getValue(t_xml_tree, "/Transaction/TransHeader/ChannelId/text()")
        if s_channel_id ~= nil then
            s_channel_id = string.trim(s_channel_id)
            s_channel_name = arr_channel_id[s_channel_id]
            if s_channel_name == nil then s_channel_name = s_channel_id end
            ApmData.replaceField("transaction.channel_code", s_channel_id)
            ApmData.replaceField("transaction.channel_name", s_channel_name)
        end
    end

    -- 网银流水号
    s_flowno = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Request/FrontTransFlowNo/text()")
    if s_flowno ~= nil then
        s_flowno = string.trim(s_flowno)
        if s_flowno ~= "" then
            ApmData.replaceField("transaction.code", s_flowno)
        end
    end

    if s_flowno == nil or s_flowno == "" then
        s_flowno = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Request/HostTransFlowNo/text()")
        if s_flowno ~= nil then
            s_flowno = string.trim(s_flowno)
            if s_flowno ~= "" then
                ApmData.replaceField("transaction.code", s_flowno)
            end
        end
    end

    return true
end

--- 解析响应
-- return
-- true: 解析成功; false: 解析失败
local function trans_parse_response(ApmData)
    -- 交易返回代码
    s_rspcode = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Response/RespCode/text()");
    if s_rspcode ~= nil then
        s_rspcode = string.trim(s_rspcode);
        ApmData.replaceField("response.code_string", s_rspcode);
        ApmData.delFields("response.code")
    end

    -- 交易返回信息
    s_rspmsg = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Response/RespMessage/text()");
    if s_rspmsg ~= nil then
        s_rspmsg = string.trim(s_rspmsg);
        ApmData.replaceField("response.error_message", s_rspmsg);
    end

    -- 网银流水号
    if s_flowno == nil or s_flowno == "" then
        s_flowno = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Response/FrontTransFlowNo/text()")
        if s_flowno ~= nil then
            s_flowno = string.trim(s_flowno)
            if s_flowno ~= "" then
                ApmData.replaceField("transaction.code", s_flowno)
            end
        end
    end

    if s_flowno == nil or s_flowno == "" then
        s_flowno = ApmXml.getValue(t_xml_tree, "/Transaction/TransBody/Response/HostTransFlowNo/text()")
        if s_flowno ~= nil then
            s_flowno = string.trim(s_flowno)
            if s_flowno ~= "" then
                ApmData.replaceField("transaction.code", s_flowno)
            end
        end
    end

    return true;
end

--- main
function post_analysis()
    local ApmData = require("ApmData")
    if ApmData.getL7Proto() ~= 50050 then return end

    local s_em_type = ApmData.getMsgType()
    if s_em_type == nil then return end

    local s_xml_string

    if s_em_type == 1 then -- 响应
        s_xml_string = ApmData.getField("request.trans.message", 1)
        if s_xml_string ~= nil then
            s_xml_string = string.trim(s_xml_string)
--            logInfo("Request:[%s]", s_xml_string)
            if protocol_detect(s_xml_string) then
                trans_parse_request(ApmData);
            end
        end

        s_xml_string = ApmData.getField("response.trans.message", 1)
        if s_xml_string ~= nil then
            s_xml_string = string.trim(s_xml_string)
--            logInfo("Response:[%s]", s_xml_string)
            if protocol_detect(s_xml_string) then
                trans_parse_response(ApmData);
            end
        end

        logInfo("移动银行(%s:%d->%s:%d) 交易名:%s|交易渠道:%s|流水号:%s|返回码:%s|%s",
            ApmData.getSrcIp(),
            ApmData.getSrcPort(),
            ApmData.getDstIp(),
            ApmData.getDstPort(),
            s_trans_name,
            s_channel_name,
            s_flowno,
            s_rspcode,
            s_rspmsg)
    end

    return;
end
